using System;
using System.Collections.Generic;
using System.Text;

namespace OneStop.Calculations
{
    /// <summary>  
    /// Defines a Gradient Factor object. 
    /// A GF Object maintains a low and high setting and is able to determine
    /// a GF for any depth between its initialisation depth (see setGfAtDepth())
    /// and the surface.
    /// </summary>
	public class Gradient : OneStopBase
    {
        #region Members

        private double gfHigh, gfLow;   // GF high and low settings
        private double gf;              // Current GF
        private double gfSlope;         // Slope of the linear equation
        private bool gfSet;             // Indicates that gf Slope has been initialised

        #endregion

        public override string ToString()
        {
            return ShortName;
        }

        #region Properties

        virtual public string ShortName
        {
            get
            {
                return string.Format("{0}-{1}", this.GfLow * 100, this.GfHigh * 100);
            }
        }

        /// <summary> 
        /// Gets current GF with bounds checking. If GF < GLLow, returns GFLow.
        /// </summary>
		virtual public double GradientFactor
		{
			get
			{
				if (gf >= gfLow)
					return gf;
				else
					return gfLow;
			}			
		}

        /// <summary> 
        /// Sets the gf for a given depth. Must be called after SetGfSlope() has initialised slope.
		/// </summary>
		virtual public double GfAtDepth
		{
			set
			{
				if ((gfSlope < 1.0) && (value >= 0))
					gf = (value * gfSlope) + gfHigh;
			}			
		}

        /// <summary> 
        /// Sets gf Slope at specified depth. Typically called once to initialise the GF slope.
        /// </summary>
		virtual public double GfSlopeAtDepth
		{
			set
			{
				if (value > 0)
				{
					gfSlope = (gfHigh - gfLow) / (0 - value);
					gfSet = true;
				}
			}			
		}

        /// <summary> 
        /// Gets/sets GF High setting. Typical (0-1.0)
        /// </summary>
		virtual public double GfHigh
		{
			get
			{
				return gfHigh;
			}
			
			set
			{
                gfHigh = value;
                NotifyPropertyChanged("GfHigh");
                NotifyPropertyChanged("ShortName");
			}			
		}

        /// <summary> 
        /// Gets/sets GF High setting. Typical (0-1.0)
        /// </summary>
		virtual public double GfLow
		{
			get
			{
				return gfLow;
			}
			
			set
			{
                gfLow = value;
                NotifyPropertyChanged("GfLow");
                NotifyPropertyChanged("ShortName");
			}			
		}

        /// <summary> 
        /// Gets/sets current GF. Typical GFLow < GF < GFHigh
        /// </summary>
		virtual public double Gf
		{
			get
			{
				return gf;
			}
			
			set
			{
				gf = value;
                NotifyPropertyChanged("Gf");
			}			
		}

		/// <summary> 
        /// Gets GF Slope (i.e. slope of the linear equation)
        /// Sets GF Slope (Required for Bean Compliance)
        /// </summary>
		virtual public double GfSlope
        {
            get
            {
                return gfSlope;
            }	

			set
			{
				gfSlope = value;
                NotifyPropertyChanged("Gf");
			}			
		}

        /// <summary> 
        /// Returns true if GF is set.
        /// </summary>
		virtual public bool GfSet
		{
			get
			{
				return gfSet;
			}
			
			set
			{
                gfSet = value;
                NotifyPropertyChanged("GfSet");
			}
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Empty constructor for Bean compliance.
        /// </summary>
        public Gradient()
        {

        }

        /// <summary> 
        /// Constructor for objects of class Gradient.
        /// </summary>
        /// <param name="gfLow">Low GF. 0 to 1.0</param>
        /// <param name="gfHigh">High GF. 0 to 1.0</param>
        public Gradient(double gfLow, double gfHigh)
        {
            this.gfHigh = gfHigh;
            this.gfLow = gfLow;
            gfSlope = 1.0;
            gf = gfLow;
            gfSet = false;
        }

        #endregion
    }
}

